//  Simple GLSL shader interface.
  
//  Relies on GLEW internally to access OpenGL extensions.
  
//  Dr. Orion Sky Lawlor, olawlor@acm.org, 2008-02-14 (public domain)
#pragma once

#include "OrionFlames.h"

namespace OrionFlames
{
//Create a complete shader object from these chunks of GLSL shader code.
//You still need to glUseProgramObjectARB(return value);
extern OFAPI GLhandleARB makeProgramObject(const char* vertex, const char* fragment);

//Converts unquoted code into a quoted C++ "const char *" string.
#define STRINGIFY(code) #code

//Allows you to hardcode your shader *without* the annoying string quotes.
#define MAKE_PROGRAM_OBJECT(vertexcode, fragmentcode) \
	makeProgramObject(#vertexcode, #fragmentcode)

//As above, but includes shared code section (for uniforms, varyings, etc).
#define MAKE_PROGRAM_OBJECT3(vertexcode, shared, fragmentcode) \
	makeProgramObject(#shared #vertexcode, #shared #fragmentcode)

//This should probably be made into a function that takes a list of strings and iterates through them, retrieving each value.
#define glUniformTextures(prog, texscale, texscalei) \
			glUniform1iARB(glGetUniformLocationARB(prog, "tex"), 0); \
			glUniform1fARB(glGetUniformLocationARB(prog, "texscale"), texscale); \
			glUniform1fARB(glGetUniformLocationARB(prog, "texscalei"), texscalei);

//Create a complete shader object from these GLSL files.
GLhandleARB makeProgramObjectFromFiles(const char* vFile = "vertex.txt", const char* fFile = "fragment.txt");

//Handy function: read an entire file into a C++ string.
std::string readFileIntoString(const char* fName);

//Set this uniform float to this value.
inline void setUniform(GLhandleARB prog, const char* name, float value)
{
	glUniform1fARB(glGetUniformLocationARB(prog, name), value);
}

inline void setUniform(GLhandleARB prog, const char *name, double value)
{
	setUniform(prog, name, (float)value);
}

//Set this uniform int to this value.
inline void setUniform(GLhandleARB prog,const char *name,int value)
{
	glUniform1iARB(glGetUniformLocationARB(prog, name), value);
}

#ifdef __OGL_VEC4_H
inline void setUniform(GLhandleARB prog,const char *name,const vec3 &value) {
	glUniform3fvARB(glGetUniformLocationARB(prog,name),1,value);
}
inline void setUniform(GLhandleARB prog,const char *name,const vec4 &value) {
	glUniform4fvARB(glGetUniformLocationARB(prog,name),1,value);
}
#endif

//These faster versions of the uniform-setting functions take a string name,
//but cache the string's looked-up "UniformLocation" index in a static variable.
#define glFastUniform(prog, name, fn, args) \
	do { static int __ul = glGetUniformLocationARB(prog, name); \
	     glUniform##fn##ARB args; } while (0)

#define glFastUniform1i(prog, name, val) glFastUniform(prog, name, 1i, (__ul, val))
#define glFastUniform1f(prog, name, val) glFastUniform(prog, name, 1f, (__ul, val))
#define glFastUniform1fv(prog, name, cnt, val) glFastUniform(prog, name, 1fv, (__ul, cnt, val))
#define glFastUniform2fv(prog, name, cnt, val) glFastUniform(prog, name, 2fv, (__ul, cnt, val))
#define glFastUniform3fv(prog, name, cnt, val) glFastUniform(prog, name, 3fv, (__ul, cnt, val))
#define glFastUniform4fv(prog, name, cnt, val) glFastUniform(prog, name, 4fv, (__ul, cnt, val))
#define glFastUniformMatrix3fv(prog, name, cnt, trs, val) glFastUniform(prog, name, Matrix3fv, (__ul, cnt, trs, val))
#define glFastUniformMatrix4fv(prog, name, cnt, trs, val) glFastUniform(prog, name, Matrix4fv, (__ul, cnt, trs, val))
}